package com.tannm.doan.taskmanager.views;

import com.tannm.doan.taskmanager.*;

import android.content.*;
import android.graphics.*;
import android.view.MotionEvent;
import android.view.View;
import android.widget.*;

public class ViewDayHourItem extends LinearLayout {
	// inner invisible view for touch mode
	public class InvisibleView extends View {
		// fields
		private final int iFrame = 2;

		// methods
		public InvisibleView(Context context) {
			super(context);
			setFocusable(false);
			LinearLayout.LayoutParams layParams = new LinearLayout.LayoutParams(
					android.view.ViewGroup.LayoutParams.FILL_PARENT,
					android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
			this.setLayoutParams(layParams);
		}

		@Override
		protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
			setMeasuredDimension(measureWidth(widthMeasureSpec),
					measureHeight(heightMeasureSpec));
		}

		private int measureWidth(int measureSpec) {
			return MeasureSpec.getSize(measureSpec);
		}

		private int measureHeight(int measureSpec) {
			return iFrame + iItemTextHeight + iFrame + iFrame;
		}
	}

	// types
	public interface OnItemClick {
		public void OnClick(ViewDayHourItem item);
	}

	// fields
	private static final String sStrHour = "00";
	private static final String sStrTime = "00:00";
	private static final String sStrUSTimeMark = "mm"; // am/pm
	private static final String sStrUSTimeAM = "am";
	private static final String sStrUSTimePM = "pm";

	// fields
	private static final int iSpace = 4;
	private static final int iFrame = 2;
	private static final Typeface tfMono = Typeface.create(Typeface.MONOSPACE,
			Typeface.NORMAL);
	private static final float fTextSize = 20;

	// fields
	private boolean b24HourMode = false;
	private int iHour = 0;
	private int iCurrentHour = -1;
	protected OnItemClick itemClick = null;

	// default hour width, full time width, am/pm width
	private int iSpaceWidthUSTimeMark = 0;
	private int iSpaceWidthHourWithUSTimeMark = 0;
	private int iSpaceWidthTimeWithUSTimeMark = 0;
	private int iSpaceWidthHourArea = 0;
	private int iSpaceWidthTimeArea = 0;
	private int iItemTextHeight = 0;

	// colors
	private final static int iColorTime = 0xFFFF8800;
	private final static int iColorMark = 0xFFAA5500;
	private final static int iColorTimeFocused = 0xFFFFCC66;
	private final static int iColorTimeTouch = 0xFF222222;
	private final int iTouchSliderColor = 0xBBFF8800;
	private final int iTouchPatternColor = 0xFF995500;

	// fields
	protected Paint mpt = null;

	// touch mode fields
	private static InvisibleView invView = null;
	private boolean bTouchedDown = false;
	private RectF rtTouchRect = new RectF();
	private RectF rtTimeTouchRect = new RectF();
	private RectF rtTouchSliderRect = new RectF();
	private RectF rectSliderArrow = new RectF();
	private int iTouchPosX = 0;
	private int iLastTimeMinutes = 0;

	// methods
	public ViewDayHourItem(Context context, int iHour, int iItemTextHeight) {
		super(context);

		this.iHour = iHour;
		this.iItemTextHeight = iItemTextHeight;

		mpt = new Paint();
		mpt.setAntiAlias(true);
		mpt.setTextSize(fTextSize);

		setWillNotDraw(false);

		setOrientation(LinearLayout.VERTICAL);
		LayoutParams lparams = new LinearLayout.LayoutParams(
				android.view.ViewGroup.LayoutParams.FILL_PARENT,
				android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
		setLayoutParams(lparams);

		// invisible view
		if (invView == null) {
			invView = new InvisibleView(context);
			invView.setVisibility(View.INVISIBLE);
		}
	}

	public void setItemClick(OnItemClick itemClick) {
		this.itemClick = itemClick;
	}

	public void setItemData(boolean b24HourMode, int iSpaceWidthHour,
			int iSpaceWidthTime, int iSpaceWidthUSTimeMark) {
		this.b24HourMode = b24HourMode;
		updateTimeFormat(b24HourMode, iSpaceWidthHour, iSpaceWidthTime,
				iSpaceWidthUSTimeMark);
		updateHeight();
	}

	public void setCurrentHour(int iCurrentHour) {
		this.iCurrentHour = iCurrentHour;
	}

	public void updateTimeFormat(boolean b24HourMode, int iSpaceWidthHour,
			int iSpaceWidthTime, int iSpaceWidthUSTimeMark) {
		this.iSpaceWidthUSTimeMark = (b24HourMode ? 0 : iSpaceWidthUSTimeMark);
		this.iSpaceWidthHourWithUSTimeMark = iSpaceWidthHour
				+ (b24HourMode ? 0 : (iSpaceWidthUSTimeMark + iFrame));
		this.iSpaceWidthTimeWithUSTimeMark = iSpaceWidthTime
				+ (b24HourMode ? 0 : (iSpaceWidthUSTimeMark + iFrame));
		this.iSpaceWidthHourArea = iSpace + iSpaceWidthHourWithUSTimeMark
				+ iSpace;
		this.iSpaceWidthTimeArea = iSpace + iSpaceWidthTimeWithUSTimeMark
				+ iSpace;
		setPadding(iSpaceWidthHourArea, iFrame + iFrame, iFrame, iFrame
				+ iFrame);
	}

	public int getHour() {
		return iHour;
	}

	public int getMinutes() {
		return iLastTimeMinutes;
	}

	public static int getTextHeight(Paint mpt) {
		mpt.setTypeface(null);
		mpt.setTextSize(fTextSize);
		mpt.setFakeBoldText(true);
		return (int) (-mpt.ascent() + mpt.descent());
	}

	public static int getSpaceWidthHour(Paint mpt) {
		mpt.setTypeface(tfMono);
		mpt.setTextSize(fTextSize);
		mpt.setFakeBoldText(true);
		return (int) mpt.measureText(sStrHour);
	}

	public static int getSpaceWidthTime(Paint mpt) {
		mpt.setTypeface(tfMono);
		mpt.setTextSize(fTextSize);
		mpt.setFakeBoldText(true);
		return (int) mpt.measureText(sStrTime);
	}

	public static int getSpaceWidthUSTimeMark(Paint mpt) {
		mpt.setTypeface(tfMono);
		mpt.setTextSize(fTextSize);
		mpt.setFakeBoldText(false);
		return (int) mpt.measureText(sStrUSTimeMark);
	}

	private int getMinHeight() {
		return getPaddingTop() + iFrame + iItemTextHeight + iFrame
				+ getPaddingBottom() - 1;
	}

	public void updateHeight() {
		this.getLayoutParams().height = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
		if (getChildCount() == 0) {
			if ((iHour >= 6) && (iHour <= 22)) {
				this.getLayoutParams().height = getMinHeight();
			} else {
				this.getLayoutParams().height = 0;
			}
		}
	}

	public boolean isMinimized() {
		return getHeight() == 0;
	}

	@Override
	protected void onFocusChanged(boolean gainFocus, int direction,
			Rect previouslyFocusedRect) {
		super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
		invalidate();
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		mpt.setAntiAlias(true);
		mpt.setTextSize(fTextSize);
		mpt.setTypeface(tfMono);
		mpt.setFakeBoldText(true);
		mpt.setShader(null);
		mpt.setUnderlineText(false);

		final boolean bIsFocused = hasFocus();
		final int iHeight = getHeight() - iFrame;
		final int iWidth = getWidth();
		final int iTimePosY = (-(int) mpt.ascent()) + iFrame + iFrame + 1;

		if (!isMinimized()) {
			getTouchRectangle();

			drawBackground(canvas, iWidth, iHeight, bIsFocused);

			drawTime(canvas, iTimePosY, iWidth, iHeight, bIsFocused);

			if (bTouchedDown) {
				getTouchSliderRectangle();
				drawTouchSlider(canvas);
				drawTouchBar(canvas);
			}
		}
	}

	private void drawBackground(Canvas canvas, int iWidth, int iHeight,
			boolean bIsFocused) {
		mpt.setTypeface(null);
		mpt.setShader(null);

		// draw touch slider background
		if (bTouchedDown) {
			mpt.setColor(iColorTime);
			canvas.drawRoundRect(rtTouchRect, 3, 3, mpt);
		}

		// draw gradient line
		LinearGradient lGrad = new LinearGradient((getWidth() >> 2), 0,
				getWidth(), 0, 0xFFFFFFFF, 0x00FFFFFF, Shader.TileMode.CLAMP);
		mpt.setShader(lGrad);
		canvas.drawLine(0, 0, getWidth(), 0, mpt);

		mpt.setShader(null);
	}

	private String getHourString() {
		if (b24HourMode) {
			return Integer.toString(iHour);
		} else {
			int iDisplayHour = iHour;
			if (iDisplayHour == 0)
				iDisplayHour = 12;
			if (iDisplayHour > 12)
				iDisplayHour -= 12;
			return Integer.toString(iDisplayHour);
		}
	}

	private String getMinutesString() {
		if (iLastTimeMinutes > 9)
			return ":" + Integer.toString(iLastTimeMinutes);
		return ":0" + Integer.toString(iLastTimeMinutes);
	}

	private String getUSTimeMark() {
		if (iHour >= 12)
			return sStrUSTimePM;
		return sStrUSTimeAM;
	}

	private void drawTime(Canvas canvas, int iTimePosY, int iWidth,
			int iHeight, boolean bIsFocused) {
		mpt.setAntiAlias(true);
		mpt.setTextSize(fTextSize);
		mpt.setTypeface(tfMono);
		mpt.setFakeBoldText(true);
		mpt.setShader(null);

		mpt.setUnderlineText(false);
		if (iCurrentHour == iHour)
			mpt.setUnderlineText(true);

		// draw hour
		final String sHour = getHourString();
		final int iStrHourWidth = (int) mpt.measureText(sHour);
		final int iTimePosX = iSpaceWidthHourArea - iStrHourWidth - iFrame
				- iSpaceWidthUSTimeMark - iSpace;
		mpt.setColor((bTouchedDown) ? iColorTimeTouch : iColorTime);
		if (bIsFocused)
			mpt.setColor(iColorTimeFocused);
		canvas.drawText(sHour, iTimePosX, iTimePosY, mpt);

		// draw minutes
		int iMarkPosX = iTimePosX + iStrHourWidth + iFrame;
		if (bTouchedDown) {
			final String sMinutes = getMinutesString();
			final int iStrMinutesWidth = (int) mpt.measureText(sMinutes);
			final int iMinutesPosX = iTimePosX + iStrHourWidth;
			iMarkPosX = iMinutesPosX + iStrMinutesWidth + iFrame;
			canvas.drawText(sMinutes, iMinutesPosX, iTimePosY, mpt);
		}

		// draw us time mark
		if (!b24HourMode) {
			mpt.setFakeBoldText(false);
			mpt.setColor(iColorMark);
			if (bIsFocused)
				mpt.setColor(iColorTimeFocused);
			canvas.drawText(getUSTimeMark(), iMarkPosX, iTimePosY, mpt);
		}

		mpt.setUnderlineText(false);
	}

	private void drawTouchSlider(Canvas canvas) {
		// draw inner background
		mpt.setShader(null);
		mpt.setColor(iColorTimeTouch);
		canvas.drawRoundRect(rtTouchSliderRect, 3, 3, mpt);

		// draw slider pattern
		mpt.setColor(iTouchPatternColor);
		mpt.setStrokeWidth(4);
		mpt.setStrokeCap(Paint.Cap.ROUND);

		rectSliderArrow.set(rtTouchSliderRect);
		final int iArrowWidth = 6;
		final int iArrowSpace = 8;
		final int iArrowCount = (int) (rtTouchSliderRect.width() / (iArrowWidth + iArrowSpace));

		final int iMargin = (int) rtTouchSliderRect.width()
				- (iArrowCount * (iArrowWidth + iArrowSpace));
		rectSliderArrow.left += iMargin;

		for (int i = 0; i < iArrowCount; i++) {
			drawTouchSliderArrow(canvas, rectSliderArrow, iArrowWidth);
			rectSliderArrow.left += iArrowWidth + iArrowSpace;
		}

		mpt.setStrokeWidth(0);
	}

	private void drawTouchSliderArrow(Canvas canvas, RectF rect, int iArrowWidth) {
		int istartX = (int) (rect.left);
		int istopX = (int) (rect.left + iArrowWidth);
		int iCenter = (int) (rect.top + (rect.height() / 2));
		canvas.drawLine(istartX, rect.top + 5, istopX, iCenter, mpt);
		canvas.drawLine(istartX, rect.bottom - 5, istopX, iCenter, mpt);
	}

	private void drawTouchBar(Canvas canvas) {
		// draw inner background
		mpt.setShader(null);
		mpt.setColor(iTouchSliderColor);

		// control ranges
		float fMaxRight = rtTouchSliderRect.right;
		rtTouchSliderRect.right = iTouchPosX;
		if (rtTouchSliderRect.right > fMaxRight)
			rtTouchSliderRect.right = fMaxRight;
		if (rtTouchSliderRect.right < rtTouchSliderRect.left)
			rtTouchSliderRect.right = rtTouchSliderRect.left;

		canvas.drawRoundRect(rtTouchSliderRect, 2, 2, mpt);
	}

	public int calculateTimeMinutes() {
		RectF rectSlider = getTouchSliderRectangle();
		if (iTouchPosX > 0) {
			if ((iTouchPosX > rectSlider.left)
					&& (iTouchPosX < rectSlider.right)) {
				float fRange = rectSlider.right - rectSlider.left;
				float fPos = iTouchPosX - rectSlider.left;
				float fStep = (fRange / 60);
				int iMinutes = (int) (fPos / fStep);
				if (iMinutes < 0)
					iMinutes = 0;
				if (iMinutes > 59)
					iMinutes = 59;

				int iModulo = iMinutes % 5;
				iMinutes = iMinutes - iModulo;

				return iMinutes;
			}
		}
		return 0;
	}

	public void doItemClick() {
		if (itemClick != null)
			itemClick.OnClick(this);
	}

	private RectF getTouchRectangle() {
		rtTouchRect.set(0, 3, getWidth() - 1, getMinHeight() - 2);
		return rtTouchRect;
	}

	private RectF getTimeTouchRectangle() {
		rtTimeTouchRect.set(iFrame, 2, iSpaceWidthTimeArea - iFrame,
				getMinHeight() - 2);
		return rtTimeTouchRect;
	}

	private RectF getTouchSliderRectangle() {
		rtTouchSliderRect.set(getTouchRectangle());
		rtTouchSliderRect.inset(2, 2);
		rtTouchSliderRect.left = iSpaceWidthTimeArea + iSpace + iSpace;
		rtTouchSliderRect.right = rtTouchSliderRect.right - iSpace - iSpace
				- iSpace;
		return rtTouchSliderRect;
	}

	private boolean touchInTimeArea(MotionEvent event) {
		RectF rect = getTimeTouchRectangle();
		if (rect.contains(event.getX(), event.getY()))
			return true;
		return false;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		boolean bHandled = false;
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			if (touchInTimeArea(event)) {
				bHandled = true;
				bTouchedDown = true;
				iLastTimeMinutes = 0;
				iTouchPosX = 0;
				enableInnerViewSpace(true);
				invalidate();
				Utils.startAlphaAnimIn(ViewDayHourItem.this);
			}
		}
		if (event.getAction() == MotionEvent.ACTION_CANCEL) {
			bHandled = true;
			bTouchedDown = false;
			iTouchPosX = 0;
			enableInnerViewSpace(false);
			invalidate();
		}
		if (event.getAction() == MotionEvent.ACTION_UP) {
			bHandled = true;
			bTouchedDown = false;
			enableInnerViewSpace(false);
			invalidate();
			doItemClick();
		}
		if (event.getAction() == MotionEvent.ACTION_MOVE) {
			bHandled = true;
			iTouchPosX = (int) event.getX();
			iLastTimeMinutes = calculateTimeMinutes();
			invalidate();
		}
		return bHandled;
	}

	private void enableInnerViewSpace(boolean bEnable) {
		if (bEnable) {
			this.addView(invView, 0);
		} else {
			this.removeView(invView);
		}
	}

}
